﻿using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using Entities;
using ServiceInterfaces;
using UnityRepository.Interfaces;
using UnityRepository.Repositories;
using Serialization;

namespace ClientProxyTests
{
  using System;
  using ClientProxies.ArchiveServiceReference;
  using Exceptions;
  using FluentAssertions;
  using NUnit.Framework;
  using Services;
    

    /// <summary>
    /// IMPORTANT: If any of the test in this class fails check if the hard-coded parameter values are in the database
    /// </summary>
  [TestFixture]
  public class ServiceAccessTests
  {
    # region Private variables

      private AuthenticationData authenticationData;
      private IUserService _userService;
      private IManCoService _manCoService;
      private IManCoRepository _manCoRepository;
      private DocumentClient _proxy;

      private String docType = null;
        private String subDocType = null;
        private String addresseeSubType = null; 
        private String accountNumber = null; 
        private String mailingName = null; 
        private IList<String> managementCompanies;
        private String investorReference = null;
        private DateTime? processingDateFrom = null;
        private DateTime? processingDateTo = null; 
        private String primaryHolder = null;
        private String agentReference = null;
        private String addresseePostCode = null;
        private String emailAddress = null;
        private String faxNumber = null;
        private DateTime? contractDate = null;
        private DateTime? paymentDate = null;
        private String documentNumber = null; 

        private Int32 startRow;
        private Int32 endRow;
        private DateTime fromDate;
        private DateTime toDate;

      #endregion
      
    [SetUp]
    public void SetUp()
      {
          _proxy = new DocumentClient();
          _proxy.Open();
          this.GetAuthData();

          fromDate = DateTime.Now.AddMonths(-1);
          toDate = DateTime.Now;

          startRow = 1;
          endRow = 10;
          managementCompanies = GenerateMancoTextList().ToList();
      }

    [Test]
    public void GivenADocumentService_WhenITryToOpenTheConnection_TheConnectionIsOpened()
    {
      var newproxy = new DocumentClient();

      newproxy.Open();

      Action act = newproxy.Open;

      act.ShouldNotThrow<UnityException>();
    }

    //*************************************************************************
    //Commented as require the correct ID from database for this all the time
    //*************************************************************************

    //[Test]
    //public void GivenADocumentService_WhenIRequestDocumentByDocId_ShouldGetResult()
    //{
    //    const string documentId = "fac0a234-1111-1111-1111-123456781234";

    //    byte[] data = _proxy.GetDocument(authenticationData, documentId);

    //    Assert.IsNotNull(data);
    //}

    //[Test]
    //public void GivenADocumentService_WhenITryASearchByGridId_ShouldGetResult()
    //{
    //    const string grid = "14315B-144548X-RTMM";
    //    endRow = 10000;
    //    DocumentSearchResultsData data = _proxy.DocumentSearch(this.authenticationData, startRow, endRow, String.Empty, grid, 1, "*",
    //                                                            String.Empty,String.Empty,String.Empty,String.Empty,String.Empty,String.Empty,
    //                                                            String.Empty,String.Empty,String.Empty);
    //    Assert.IsNotNull(data);
        
    //}

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByAnyParameters_ShouldGetResult()
    {
        docType = "CHQ";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria( docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);
        
        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        Assert.IsNotNull(data);

       
    }
    
    [Test]
    public void GivenADocumentService_WhenITryASearch_ByDocType_ShouldGetDocumentsOfSameDocTypeOrNoDocuments()
    {
        docType = "CHQ";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);
        
        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlyDocType = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "DOCUMENT_TYPE" && mapindex.IndexValue != docType));
        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlyDocType);
    }

    [Test]
    public void GivenADocumentService_WhenITryASearch_BySubDocType_ShouldGetDocumentsOfSameSubDocTypeOrNoDocuments()
    {
        docType = "CHQ";
        subDocType = "DST";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);
        
        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlySubDocType = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "DOCUMENT_SUB_TYPE" && mapindex.IndexValue != subDocType));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlySubDocType);
    }

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByManCo_ShouldGetDocumentsOfSameManCoOrNoDocuments()
    {
        //024 - Barclays Asset Management
        managementCompanies=new List<string>();
        String manCo = "024";
        managementCompanies.Add(manCo);
     
        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                           processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                           faxNumber, contractDate, paymentDate, documentNumber);
        
        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlyManCo = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "MANAGEMENT_COMPANY" && mapindex.IndexValue !=manCo));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlyManCo);
    }

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByProcessingDates_ShouldGetDocumentsBetweenProcessingDateRangeOrNoDocuments()
    {
        fromDate = DateTime.Now.AddMonths(-1);
        toDate = DateTime.Now;

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);

        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool inProcDateRange = data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "PROCESSING_DATE" && DateTime.Parse(mapindex.IndexValue) >= fromDate
                                                                                                                                && DateTime.Parse(mapindex.IndexValue) <= toDate));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || inProcDateRange);
    }

      /******************************************
       * Sub Types and related properties
       ******************************************/

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByAddresseeSubType_ShouldGetDocumentsByAddresseeSubType()
    {
        addresseeSubType = "Agent";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);

        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlyAddresseeSubType = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "ADDRESSEE_SUB_TYPE" && mapindex.IndexValue != addresseeSubType));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlyAddresseeSubType);
    }

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByMailingName_ShouldGetDocumentsByMailingName()
    {
        mailingName = "Cofunds Limited";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);

        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlyMailingName = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "MAILING_NAME" && mapindex.IndexValue != mailingName));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlyMailingName);
    }

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByPrimaryHolderName_ShouldGetDocumentsByPrimaryHolderName()
    {
        primaryHolder = "Fund Settle EOC Nominees Limited";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);

        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlyPrimaryHolder = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "PRIMARY_HOLDER_NAME" && mapindex.IndexValue != primaryHolder));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlyPrimaryHolder);
    }

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByAddresseePostCode_ShouldGetDocumentsByAddresseePostCode()
    {
        addresseePostCode = "EC4M 5SB";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);

        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlyAddresseePostCode = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "ADDRESSEE_POSTCODE" && mapindex.IndexValue != addresseePostCode));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlyAddresseePostCode);
    }

    /******************************************
     * Type = CNF and properties
     ******************************************/

    [Test]
    public void GivenADocumentService_WhenITryASearch_ByDocumentReference_ShouldGetDocumentsByDocumentReference()
    {
        documentNumber = "3293 3671";

        var indexNameCriteraService = new IndexNameCriteraService();
        var searchCriteria = indexNameCriteraService.BuildSearchCriteria(docType, subDocType, addresseeSubType, accountNumber, mailingName, managementCompanies, investorReference,
                                                                            processingDateFrom, processingDateTo, primaryHolder, agentReference, addresseePostCode, emailAddress,
                                                                            faxNumber, contractDate, paymentDate, documentNumber);

        DocumentSearchResultsIndexedData data = _proxy.DocumentSearchMapVerbose(this.authenticationData, startRow, endRow, 1, fromDate, toDate, searchCriteria);

        bool hasOnlyDocumentReference = !data.DocumentList.Any(doc => doc.MappedIndexes.Any(mapindex => mapindex.IndexName == "DOCUMENT_REFERENCE" && mapindex.IndexValue != documentNumber));

        Assert.IsTrue(data == null || data.DocumentList.Count <= 0 || hasOnlyDocumentReference);
    }

    #region Private Methods

    private void GetAuthData()
    {
        this.authenticationData = new AuthenticationData
        {
            Source = "Unity",
            Destination = "NT-Archive",
            UserName = "paul",
            PassToken = "9F33A7C798AF6FD6ABB28049D9C1B3EDFA2FD24A",
            RequestId = "1",
            CurrentDateTime = DateTime.Now,
            OriginatingUser = "unity"
        };
    }
      
    private IList<String> GenerateMancoTextList()
    {
        _userService = new UserService();
        _manCoRepository = new ManCoRepository(ConfigurationManager.ConnectionStrings["Unity"].ConnectionString);
        _manCoService = new ManCoService(_manCoRepository);
        var manCoTextList = new List<String>();
        IList<ManCo> manCos = _manCoService.GetManCos();

        foreach (ManCo manCo in manCos)
        {
            manCoTextList.Add(manCo.Code);
        }

        return manCoTextList;
    }
    #endregion

  }
}
